#include "ProfileManager.h"
#include "GamePlayState.h"
#include "AchievementManager.h"
using namespace AchievementSystem;

#include "Game.h"
#include <sstream>
#include <fstream>
#include "../TinyXML/tinyxml.h"
#include <ShlObj.h>
#include "..\SGD Wrappers\SGD_String.h"
#include <Windows.h>

ProfileManager* ProfileManager::pInstance = nullptr;

ProfileManager* ProfileManager::GetInstance( void )
{
	// Allocate the static pointer if necessary
	if( pInstance == nullptr )
		pInstance = new ProfileManager;

	// Return the singleton
	return pInstance;
}
void ProfileManager::DeleteInstance( void )
{
	delete pInstance;
	pInstance = nullptr;
}


ProfileManager::ProfileManager(void)
{
	curProfile = 0;
	for(int i = 0; i < 5; ++i)
	{
		profiles[i] = nullptr;
	}
}


ProfileManager::~ProfileManager(void)
{
	for(int i = 0; i < 5; ++i)
	{
		delete profiles[i];
	}
}


Profile& ProfileManager::getCurProfile(void)
{
	return *profiles[curProfile];
}
Profile* ProfileManager::getProfile(int profileToGet)
{
	return profiles[profileToGet];
}

void ProfileManager::setCurProfile(int profile)
{
	curProfile = profile;
	if(profiles[profile] == nullptr)
	{
		createProfile(profile);
	}

	//////////////////////////////////////////////////
	// Load the achievements for this profile:

	// Clear current achievements.
	AchievementManager::GetInstance().ClearAchievements();
	if(AchievementManager::GetInstance().LoadAchievements("XML/achievements/Achievements.xml") == false)
		assert(false && "Could not load \"XML\\achievements\\Achievements.xml\". Make sure the file exists.");

	// Create the filename based on the profile index.
	ostringstream filename;
	filename << "XML/achievements/Slot" << profile + 1 << " Achievements.txt";

	// Open the file.
	ifstream input;
	input.open(filename.str().c_str());

	if(input.is_open())
	{
		string s;

		// Grab all text at once.
		getline(input, s, '\0');

		// Close the file.
		input.close();

		istringstream iss(s);

		string name;
		int value;

		getline(iss, name, '\t');
		iss >> value;
		while(iss.eof() == false)
		{
			AchievementManager::GetInstance().SetAchievementProgress(name, value);

			getline(iss, name, '\t');
			iss >> value;
		}
	}
}


bool ProfileManager::createProfile(int profileToCreate)
{
	if(profiles[profileToCreate] == nullptr)
	{
		profiles[profileToCreate] = new Profile();

		return true;
	}
	else
	{
		return false;
	}
}

void ProfileManager::loadProfiles()
{	
	wchar_t* localappdata = nullptr;

	SHGetKnownFolderPath( FOLDERID_LocalAppData, 0, NULL, &localappdata );

	wstringstream length;

	length << localappdata;

	int bytes = length.str().size();
	int strlength = length.str().length();

	char* notsowidenow = new char[strlength+1];

	WSTR_TO_CSTR(notsowidenow, bytes+1, localappdata);

	string loadme = notsowidenow;
	delete [] notsowidenow;
	loadme += "\\S.M.A.R.T. Profiles\\profiles.xml";
	
	CoTaskMemFree((void*)localappdata);

	TiXmlDocument doc;

	doc.LoadFile( loadme.c_str() );
	
	TiXmlElement* root = doc.RootElement();

	if(root	!= nullptr)
	{
		//Check for profiles
		 if(root->NoChildren())
		 {
			createProfile(0);
		 }
		 else
		 {
			//Get the last selected profile
			root->Attribute("activeProfile",&curProfile);

			int numProfiles = 0;
			for(TiXmlElement* profileEl = root->FirstChildElement("profile"); profileEl != NULL && numProfiles < 5; profileEl = profileEl->NextSiblingElement("profile"))
			{
				Profile* tempProfile = new Profile;

				TiXmlElement* nameEl =  profileEl->FirstChildElement("name");
				tempProfile->setName( nameEl->GetText() );

				//Check to see if the profile exists
				if(tempProfile->getName() != "NULL")
				{
					TiXmlElement* volumeEl = nameEl->NextSiblingElement("volume");
					int volume = 0;
					volumeEl->Attribute("master", &volume);
					tempProfile->setMasterVolume(volume);
					volumeEl->Attribute("sfx", &volume);
					tempProfile->setSFXVolume( volume);
					volumeEl->Attribute("music", &volume);
					tempProfile->setMusicVolume(volume);

					TiXmlElement* levelEl = volumeEl->NextSiblingElement("levelsUnlocked");
					string levelStr = levelEl->GetText();
					int levelsUnlocked = atoi(levelStr.c_str());
					tempProfile->setLevelsUnlocked(levelsUnlocked);

					TiXmlElement* timeEl = levelEl->NextSiblingElement("times");
					double time;

					for (int i = 0; i < 25; i++)
					{
						ostringstream oss;
						oss << "L" << i;
						timeEl->Attribute(oss.str().c_str(), &time);
						tempProfile->setBestTime(i, (float)time);
					}

					TiXmlElement* controlsEl = levelEl->NextSiblingElement("controls");
					string controlsStr = controlsEl->GetText();
					char controls = controlsStr[0];
					controls -= 48;
					tempProfile->setControlScheme(controls);

					TiXmlElement* windowEl = controlsEl->NextSiblingElement("isWindowed");
					string windowStr = windowEl->GetText();
					if(windowStr[0] == '0')
					{
						tempProfile->setIsWindowed(false);
					}
					else
					{
						tempProfile->setIsWindowed(true);
					}
					Game::GetInstance()->SetIsWindowed(tempProfile->getIsWindowed());
				}
				else
				{
					//Set the profile to null if it doesn't exist
					delete tempProfile;
					tempProfile = nullptr;
				}

				
				profiles[numProfiles] = tempProfile;
				++numProfiles;
			}
		 }
	 }
	else
	{
		assert("XML/profiles.xml not found!");
		createProfile(0);
	}
}	 
void ProfileManager::saveProfiles() const
{
	wchar_t* localappdata = nullptr;

	SHGetKnownFolderPath( FOLDERID_LocalAppData, 0, NULL, &localappdata );

	wstringstream length;

	length << localappdata;

	int bytes = length.str().size();
	int strlength = length.str().length();

	char* notsowidenow = new char[strlength+1];

	WSTR_TO_CSTR(notsowidenow, bytes+1, localappdata);

	string loadme = notsowidenow;
	delete [] notsowidenow;
	loadme += "\\S.M.A.R.T. Profiles\\";
	CreateDirectoryA( loadme.c_str(), NULL );

	loadme += "profiles.xml";
	
	CoTaskMemFree((void*)localappdata);

	TiXmlDocument doc;
	TiXmlElement* profilesEl = new TiXmlElement("profiles");
	profilesEl->SetAttribute("activeProfile",curProfile);
	doc.LinkEndChild(profilesEl);

	for(int profileToSave = 0; profileToSave < 5; ++profileToSave)
	{
		Profile* tempProfile = profiles[profileToSave];
		if(tempProfile != nullptr)
		{
			TiXmlElement* profileEl = new TiXmlElement("profile");
			profilesEl->LinkEndChild(profileEl);

			TiXmlElement* nameEl = new TiXmlElement("name");
			nameEl->LinkEndChild( new TiXmlText(tempProfile->getName().c_str()));
			profileEl->LinkEndChild(nameEl);

			TiXmlElement* volumeEl = new TiXmlElement("volume");
			volumeEl->SetAttribute("master",tempProfile->getMasterVolume());
			volumeEl->SetAttribute("music", tempProfile->getMusicVolume());
			volumeEl->SetAttribute("sfx", tempProfile->getSFXVolume());
			profileEl->LinkEndChild(volumeEl);

			
			TiXmlElement levelEl("levelsUnlocked");
			levelEl.LinkEndChild( new TiXmlText( to_string(tempProfile->getLevelsUnlocked()).c_str()) );
			profileEl->InsertEndChild(levelEl);

			TiXmlElement* timeEl = new TiXmlElement("times");
			for (int i = 0; i < 25; i++)
			{
				ostringstream oss;
				oss << "L" << i;

				if(profileToSave == curProfile && i == GamePlayState::GetInstance()->GetlevelManager().GetCurLevel() && GamePlayState::GetInstance()->GetPlayer() != nullptr)
				{
					if((GamePlayState::GetInstance()->GetPlayer()->GetCurTime() < tempProfile->getBestTime(i) || tempProfile->getBestTime(i) == 0.0f) 
						&& GamePlayState::GetInstance()->GetPlayer()->GetIsOver())
					{
						timeEl->SetDoubleAttribute(oss.str().c_str(), (double)GamePlayState::GetInstance()->GetPlayer()->GetCurTime());
						tempProfile->setBestTime(i, GamePlayState::GetInstance()->GetPlayer()->GetCurTime());
					}
				}
				else
					timeEl->SetDoubleAttribute(oss.str().c_str(), (double)tempProfile->getBestTime(i));				
			}
			profileEl->LinkEndChild(timeEl);

			TiXmlElement controlEl("controls");
			controlEl.LinkEndChild( new TiXmlText( to_string(tempProfile->getControlScheme()).c_str()) );
			profileEl->InsertEndChild(controlEl);

			TiXmlElement windowEl("isWindowed");
			windowEl.LinkEndChild( new TiXmlText( to_string(tempProfile->getIsWindowed()).c_str()) );
			profileEl->InsertEndChild(windowEl);
		}
		else
		{
			TiXmlElement* profileEl = new TiXmlElement("profile");
			profilesEl->LinkEndChild(profileEl);

			TiXmlElement* nameEl = new TiXmlElement("name");
			nameEl->LinkEndChild( new TiXmlText("NULL"));
			profileEl->LinkEndChild(nameEl);

			TiXmlElement* volumeEl = new TiXmlElement("volume");
			volumeEl->SetAttribute("master",0);
			volumeEl->SetAttribute("music", 0);
			volumeEl->SetAttribute("sfx", 0);
			profileEl->LinkEndChild(volumeEl);

			
			TiXmlElement levelEl("levelsUnlocked");
			levelEl.LinkEndChild( new TiXmlText( to_string(-1).c_str()) );
			profileEl->InsertEndChild(levelEl);

			//TiXmlElement* timeEl = new TiXmlElement("times");
			//for (int i = 0; i < 25; i++)
			//{
			//	ostringstream oss;
			//	oss << "L" << i;

			//	if(profileToSave == curProfile && i == GamePlayState::GetInstance()->GetlevelManager().GetCurLevel() && GamePlayState::GetInstance()->GetPlayer() != nullptr)
			//	{
			//		if((GamePlayState::GetInstance()->GetPlayer()->GetCurTime() < tempProfile->getBestTime(i) || tempProfile->getBestTime(i) == 0.0f) 
			//			&& GamePlayState::GetInstance()->GetPlayer()->GetIsOver())
			//		{
			//			timeEl->SetDoubleAttribute(oss.str().c_str(), (double)GamePlayState::GetInstance()->GetPlayer()->GetCurTime());
			//			tempProfile->setBestTime(i, GamePlayState::GetInstance()->GetPlayer()->GetCurTime());
			//		}
			//	}
			//	else
			//		timeEl->SetDoubleAttribute(oss.str().c_str(), (double)tempProfile->getBestTime(i));				
			//}
			//profileEl->LinkEndChild(timeEl);

			TiXmlElement controlEl("controls");
			controlEl.LinkEndChild( new TiXmlText( to_string(0).c_str()) );
			profileEl->InsertEndChild(controlEl);

			TiXmlElement windowEl("isWindowed");
			windowEl.LinkEndChild( new TiXmlText( to_string(true).c_str()) );
			profileEl->InsertEndChild(windowEl);
		}

	}
	doc.SaveFile(loadme.c_str());

	//////////////////////////////////////////////////
	// Save the achievements for this profile.

	// Create the filename based on the profile index.
	ostringstream filename;
	filename << "XML/achievements/Slot" << curProfile + 1 << " Achievements.txt";

	// Open the file.
	ofstream output;
	output.open(filename.str().c_str(), ios_base::trunc);

	if(output.is_open())
	{
		AchievementManager& manager = AchievementManager::GetInstance();

		// Save the completed achievements first.
		for(unsigned int i = 0; i < manager.CompleteAchievements().size(); ++i)
		{
			output << manager.CompleteAchievements()[i].GetName() << '\t';
			output << manager.CompleteAchievements()[i].GetValue() << '\n';
		}

		// Save the incomplete achievements next.
		for(unsigned int i = 0; i < manager.IncompleteAchievements().size(); ++i)
		{
			output << manager.IncompleteAchievements()[i].GetName() << '\t';
			output << manager.IncompleteAchievements()[i].GetValue() << '\n';
		}

		output.close();
	}
}

void ProfileManager::deleteProfile(int profileToDelete)
{
	if(profiles[profileToDelete] != nullptr)
	{
		delete profiles[profileToDelete];
		profiles[profileToDelete] = nullptr;

		int tempNum = -1;
		while(profiles[curProfile] == nullptr)
		{
			if(tempNum < 4)
			{
				tempNum += 1;
				curProfile = tempNum;
			}
			else
			{
				curProfile = 0;
				createProfile(0);
			}
		}
	}
	else
	{
	}
}
